﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace StackVsArrayTemplate
{
	class Program
	{
		class StackTemplate<T>
		{
			// максимальный размер стека
			private int _maxSize;
			// массив элементов стека
			private T[] items;
			// индекс верхнего элемента в стеке
			private int _top = -1;
			// максимальный размер стека по умолчанию
			public readonly static int MaxSize = 2;

			// конструктор по умолчанию
			public StackTemplate() 
			{				
				_maxSize = MaxSize;			// установим максимальное число элементов стека
				items = new T[_maxSize];	// создадим массив объектов для хранения элементов стека
			}

			// свойство получающее "число элементов в стеке"
			public int Size
			{
				get
				{
					return (_top + 1);
				}
			}

			// свойство проверки на "пустой стек"
			public bool IsEmpty
			{
				get
				{
					return (_top < 0);
				}
			}

			// метод возвращает верхний элемент из стека
			public T Top()
			{
				// Если стек пуст - выбрасываем исключение и выходим
				if (IsEmpty)
					throw new Exception("Стек пуст!");

				// возвращаем верхний элемент стека по индексу вершины
				return items[_top];
			}

			public void SetCapacity(int value)
			{
				if (value == this._maxSize)
				{
					return;
				}
				else
					if (value < this._maxSize)
					{
						throw new Exception("Размер массива не может быть установлен меньше текущего");
					}
					else
						if (value > 0)
						{
							// создадим новый массив увеличенный в 2 раза
							T[] newItems = new T[items.Length * 2];
							// максимальный размер стека изменяем
							_maxSize = newItems.Length;
							// копируем старый массив в новый
							items.CopyTo(newItems, 0);
							// меняем ссылку на новый массив элементов
							items = newItems;
						}
			}
			// метод добавляющий элемент в стек (количество элементов в стеке увеличивается) 
			public void Push(T element)
			{
				// Если достигнуто максимальное значение - выбросим исключение и выходим
				if (Size == _maxSize)
				{
					SetCapacity(2 * this._maxSize);
				}
				// добавим элемент в стек
				this.items[++_top] = element;
			}

			// метод выталкивающий элемент из стека (количество элементов стека уменьшается)
			public T Pop()
			{
				T StackElement;
				if (IsEmpty)
					throw new Exception("Стек пуст!");
				StackElement = this.items[_top];
				//items[_top--] = null;
				this._top--; // уменьшим укзатель на вершину стека
				return StackElement;
			}

			// метод выводит элементы стека сверху вниз
			public void Print()
			{
				// Если стек пуст - выбрасываем исключение и выходим
				if (IsEmpty)
					throw new Exception("Стек пуст!");

				for (int i = _top; i >= 0; i--)
					Console.WriteLine(this.items[i]);
			}
		}

		static void Main(string[] args)
		{
			// создадим стек
			StackTemplate<int> arrStack = new StackTemplate<int>();
			// заполним его элементами
			arrStack.Push(10);
			arrStack.Push(20);
			arrStack.Pop();		// вытолкнем элемент из стека
			arrStack.Push(30);
			arrStack.Push(40);
			arrStack.Push(50);
			arrStack.Push(60);

			// выведем содержимое стека
			arrStack.Print();

			Console.ReadKey(true);
		}
	}
}
